package org.tbjd.client.dndControllers.taskList;

/*
 * Copyright 2008 Fred Sauer
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

import java.util.HashMap;
import java.util.Map;

import org.tbjd.client.constants.NotificationsConstants;
import org.tbjd.client.exceptions.NoUpperDecisionmakerFoundException;
import org.tbjd.client.exceptions.NoUpperMediatorFoundException;
import org.tbjd.client.interfaces.Decisionmaker;
import org.tbjd.client.utils.FlexTableUtil;

import com.allen_sauer.gwt.dnd.client.DragContext;
import com.allen_sauer.gwt.dnd.client.PickupDragController;
import com.allen_sauer.gwt.dnd.client.VetoDragException;
import com.allen_sauer.gwt.dnd.client.drop.BoundaryDropController;
import com.allen_sauer.gwt.dnd.client.util.CoordinateLocation;
import com.allen_sauer.gwt.dnd.client.util.DOMUtil;
import com.allen_sauer.gwt.dnd.client.util.LocationWidgetComparator;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.IndexedPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * Allows table rows to dragged by their handle.
 */
public final class FlexTableRowDragController extends PickupDragController implements Decisionmaker {

	private static final String CSS_DEMO_FLEX_TABLE_ROW_EXAMPLE_TABLE_PROXY = "demo-FlexTableRowExample-table-proxy";

	private FlexTable draggableTable;

	private int dragRow;

	Map<Integer, Integer> map = null;

	private boolean dropAllowed = true;
	
	private IndexedPanel flexTableRowsAsIndexPanel = new IndexedPanel() {

		public Widget getWidget(int index) {
			return draggableTable.getWidget(index, 1);
		}

		public int getWidgetCount() {
			return draggableTable.getRowCount();
		}

		public int getWidgetIndex(Widget child) {
			throw new UnsupportedOperationException();
		}

		public boolean remove(int index) {
			throw new UnsupportedOperationException();
		}
	};
	
	public FlexTableRowDragController(AbsolutePanel boundaryPanel) {
		super(boundaryPanel, false);
		setBehaviorDragProxy(true);
		setBehaviorMultipleSelection(false);
	}
	
	public void previewDragEnd() throws VetoDragException {
		int targetRow = DOMUtil.findIntersect(flexTableRowsAsIndexPanel,
				new CoordinateLocation(context.mouseX, context.mouseY),
				LocationWidgetComparator.BOTTOM_HALF_COMPARATOR) - 1;
		
		this.map = new HashMap<Integer, Integer>();
		
		this.map.put(NotificationsConstants.DRAGGING_TREEGRIDITEM_SOURCE, this.getDragRow()-1);
		this.map.put(NotificationsConstants.DRAGGING_TREEGRIDITEM_TARGET, targetRow-1);
		
		decide(map);
		if(dropAllowed){
			super.previewDragEnd();
		}else{
			throw new VetoDragException();
		}
	}
	
	@Override
	public void dragEnd() {
		super.dragEnd();

		// cleanup
		draggableTable = null;
	}

	@Override
	public void setBehaviorDragProxy(boolean dragProxyEnabled) {
		if (!dragProxyEnabled) {
			// TODO implement drag proxy behavior
			throw new IllegalArgumentException();
		}
		super.setBehaviorDragProxy(dragProxyEnabled);
	}

	@Override
	protected BoundaryDropController newBoundaryDropController(
			AbsolutePanel boundaryPanel, boolean allowDroppingOnBoundaryPanel) {
		if (allowDroppingOnBoundaryPanel) {
			throw new IllegalArgumentException();
		}
		return super.newBoundaryDropController(boundaryPanel,
				allowDroppingOnBoundaryPanel);
	}

	@Override
	protected Widget newDragProxy(DragContext context) {
		FlexTable proxy;
		proxy = new FlexTable();
		proxy.addStyleName(CSS_DEMO_FLEX_TABLE_ROW_EXAMPLE_TABLE_PROXY);
		draggableTable = (FlexTable) context.draggable.getParent();
		dragRow = getWidgetRow(context.draggable, draggableTable);
		FlexTableUtil.copyRow(draggableTable, proxy, dragRow, 0);
		return proxy;
	}

	public FlexTable getDraggableTable() {
		return draggableTable;
	}

	public int getDragRow() {
		return dragRow;
	}

	private int getWidgetRow(Widget widget, FlexTable table) {
		for (int row = 0; row < table.getRowCount(); row++) {
			for (int col = 0; col < table.getCellCount(row); col++) {
				Widget w = table.getWidget(row, col);
				if (w.equals(widget)) {
					return row;
				}
			}
		}
		throw new RuntimeException("Unable to determine widget row");
	}

	public void decide(Object action){
		try {
			delegate(action);
		} catch (NoUpperDecisionmakerFoundException e) {
			e.printStackTrace();
		} catch (NoUpperMediatorFoundException e) {
			e.printStackTrace();
		}
	}

	public void delegate(Object action) throws NoUpperDecisionmakerFoundException, NoUpperMediatorFoundException {
		// passes info to the first responsible
		Widget parent = ((Widget) this.context.draggable).getParent();
		while (parent != null && parent instanceof Decisionmaker == false) {
			parent = ((Widget) parent).getParent();
		}
		if (parent != null) {
			//TODO [1] when moving row up/down, call delegate...
			//dropAllowed = (Boolean) ((Decisionmaker) parent).decide(action);
		} else {
			throw new NoUpperDecisionmakerFoundException();
		}
	}

	public void handle(Object action) {
		
	}
}
